Apk 反编译和压缩的体积问题

这段时间在做 Android 多渠道可自定义打包的工作,测试过程中发现经过反编译后再重新压缩签名打包后的 apk 文件总是要比原文件更小一些。

而且在部分游戏 apk 中反编译压缩重新出包甚至会导致游戏动画加载黑屏的情况。

问题定位

apk 文件也是一个压缩文件,可以使用 zipinfo 命令查看压缩信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>> zipinfo test.apk

Zip file size: 17426 bytes, number of entries: 12
-rw---- 0.0 fat 2132 b- defN 80-000-00 00:00 AndroidManifest.xml
-rw---- 2.4 fat 765 b- defN 80-000-00 00:00 META-INF/CERT.RSA
-rw---- 2.4 fat 836 b- defN 80-000-00 00:00 META-INF/CERT.SF
-rw---- 2.4 fat 793 b- defN 80-000-00 00:00 META-INF/MANIFEST.MF
-rw---- 2.4 fat 10656 b- defN 80-000-00 00:00 classes.dex
-rw---- 2.4 fat 642 b- stor 80-000-00 00:00 res/drawable-hdpi-v4/ic_launcher.png
-rw---- 2.4 fat 566 b- stor 80-000-00 00:00 res/drawable-mdpi-v4/ic_launcher.png
-rw---- 2.4 fat 688 b- stor 80-000-00 00:00 res/drawable-xhdpi-v4/ic_launcher.png
-rw---- 2.4 fat 824 b- stor 80-000-00 00:00 res/drawable-xxhdpi-v4/ic_launcher.png
-rw---- 0.0 fat 608 b- defN 80-000-00 00:00 res/layout/view.xml
-rw---- 0.0 fat 236 b- defN 80-000-00 00:00 res/xml/methods.xml
-rw---- 0.0 fat 1904 b- stor 80-000-00 00:00 resources.arsc
12 files, 20650 bytes uncompressed, 10917 bytes compressed: 47.1%

stor 表示压缩类型是 store,即不压缩,defN 表示默认压缩, 参考 oracle zipinfo

可以发现,Android apk 对于很多媒体资源类型的文件是不压缩的。而如果我在反编译之后直接使用 zip 命令压缩打包,那默认会对所有文件做压缩处理,最终得到的 apk 体积就会更小一些。

这样做自然是有风险的,经过测试,如果对一个游戏包做这样的处理,有可能会导致游戏打开直接黑屏,实际上它应该是有一段开屏动画的。Android 游戏的开屏动画往往是一个视频,经过压缩后可能就无法正常播放。

非压缩处理

参考官方文档的说明, 特别是对于游戏类的 App 而言,对这类文件需要按非压缩类型处理。处理方式:

zip -rn .mp4:.flv:.mp3:.gif:.lua:assets/bundle.json

  • -n 表示不压缩此后缀的文件,多个规则用:隔开
  • -x 表示忽略该文件,不加入压缩包

实际上,使用 apktool 反编译后的文件夹里有一个配置文件apktool.yml ,里面有一项 doNotCompress

1
2
3
4
5
6
7
doNotCompress:
- resources.arsc
- assets/.appkey
- png
- jpg
- ogg
- mp3

表示原 apk 中以非压缩形式存储的文件类型/文件。因此如果我们需要在反编译之后做自定义操作,并使用 zip 打包的话,可以结合 apktool.yml 这个文件对原 apk 包内的非压缩文件做特殊处理。